package com.demo.redis.redis;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RTopic;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

/**
 * redisson客户端功能测试
 */
@Slf4j
@Service
public class RedissonService {

    @Resource
    private RedissonClient redissonClient;

    /**
     * 通过单元测试，在同一线程内获取锁，是否获取同一个锁
     * @param key key
     */
    public void watchDog(String key) {
        log.info("开始获取锁");
        RLock lock = redissonClient.getLock(key);
        log.info("准备上锁");
        lock.lock();
    }

    /**
     * 子线程加锁，但是没有释放锁，线程结束。主线程无法获取锁，子线程的锁不断续期，导致死锁。
     * 因为redisson client实例没有销毁，watchdog机制会不断续期。除非redisson client实例销毁或断开redis链接
     * @param key key
     * @return true-key已经上锁，false-key未上锁
     * @throws InterruptedException 异常
     */
    public boolean diffThreadLock(String key) throws InterruptedException {
        new Thread(() -> {
            RLock lock = redissonClient.getLock(key);
            lock.lock();
            log.info("子线程加锁");
        }).start();

        TimeUnit.SECONDS.sleep(1);

        RLock lock = redissonClient.getLock(key);
        return lock.isLocked();
    }

    /**
     * 测试子线程对key获取锁，主线程尝试对key进行获取锁
     * @param key key
     * @return true-获取锁成功，false-获取锁失败
     * @throws InterruptedException 异常
     */
    public boolean tryLock(String key) throws InterruptedException {
        new Thread(() -> {
            RLock lock = redissonClient.getLock(key);
            lock.lock();
        }).start();
        Thread.sleep(1000);

        RLock lock = redissonClient.getLock(key);
        return lock.tryLock(10, 100, TimeUnit.SECONDS);
    }

    /**
     * 测试使用redis进行发布/订阅
     */
    public void pubAndSub() {
        String topic = "test_topic";
        RTopic topic1 = redissonClient.getTopic(topic);
        topic1.addListener(String.class, (channel, msg) -> log.info("消费者1：" + msg));

        RTopic topic2 = redissonClient.getTopic(topic);
        topic2.addListener(String.class, (channel, msg) -> log.info("消费者2：" + msg));

        RTopic topic3 = redissonClient.getTopic(topic);
        for (int i = 0; i < 10; i++) {
            topic3.publish("广播消息" + i);
        }
    }
}
